package test2.shardingjdbc;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSource;

import com.dangdang.ddframe.rdb.sharding.api.ShardingDataSource;
import com.dangdang.ddframe.rdb.sharding.api.ShardingValue;
import com.dangdang.ddframe.rdb.sharding.api.rule.DataSourceRule;
import com.dangdang.ddframe.rdb.sharding.api.rule.ShardingRule;
import com.dangdang.ddframe.rdb.sharding.api.rule.TableRule;
import com.dangdang.ddframe.rdb.sharding.api.strategy.database.DatabaseShardingStrategy;
import com.dangdang.ddframe.rdb.sharding.api.strategy.database.SingleKeyDatabaseShardingAlgorithm;
import com.dangdang.ddframe.rdb.sharding.api.strategy.table.SingleKeyTableShardingAlgorithm;
import com.dangdang.ddframe.rdb.sharding.api.strategy.table.TableShardingStrategy;
import com.google.common.collect.Range;

public class App {
	
////////////////////////////////////////////////////////////////////
//	_ooOoo_                               //  
//	o8888888o                              //      
//	88" . "88                              //      
//	(| -_- |)                              //      
//	O\  =  /O                              //  
//____/`---'\____                           //                          
//.'  \\|     |//  `.                         //  
///  \\|||  :  |||//  \                        //      
///  _||||| -:- |||||-  \                       //  
//|   | \\\  -  /// |   |                       //  
//| \_|  ''\---/''  |_/ |                       //          
//\  .-\__  `-`  ___/-. /                       //          
//___`. .'  /--.--\  `. . ___                     //      
//."" '<  `.___\_<|>_/___.'  >'"".                  //  
//| | :  `- \`.;`\ _ /`;.`/ - ` : | |                 //      
//\  \ `-.   \_ __\ /__ _/   .-` /  /                 //  
//========`-.____`-.___\_____/___.-`____.-'========         //      
//`=---='                              //  
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        //  
//佛祖保佑       永无BUG     永不修改                  		  //  
////////////////////////////////////////////////////////////////////

	
	public static void main(String[] args) throws SQLException {

		Map<String, DataSource> dataSourceMap = new HashMap<>();
		dataSourceMap.put("ds_0", createDataSource("ds_0"));
//		dataSourceMap.put("ds_1", createDataSource("ds_1"));
//		真实的数据源可以使用任意一种数据库连接池，这里使用DBCP来举例
		
		DataSourceRule dataSourceRule = new DataSourceRule(dataSourceMap);
//		这里构造器需要一个入参：数据源名称与真实数据源之间的映射关系，这个关系的构造方法如下
		
		//使用了默认策略配置
		TableRule orderTableRule = new TableRule("t_order", Arrays.asList("t_order_0", "t_order_1", "t_order_2"), dataSourceRule);
		ShardingRule shardingRule = new ShardingRule(dataSourceRule, Arrays.asList(orderTableRule),/*
				new DatabaseShardingStrategy("id", new SingleKeyDatabaseShardingAlgorithm<Comparable<Integer>>() {

					@Override
					public String doEqualSharding(Collection<String> dataSourceNames,
							ShardingValue<Comparable<Integer>> shardingValue) {
						return "ds_0";
					}

					@Override
					public Collection<String> doInSharding(Collection<String> dataSourceNames,
							ShardingValue<Comparable<Integer>> shardingValue) {
						return Arrays.asList("ds_0");
					}

					@Override
					public Collection<String> doBetweenSharding(Collection<String> dataSourceNames,
							ShardingValue<Comparable<Integer>> shardingValue) {
						return Arrays.asList("ds_0");
					}
				}), */
                new TableShardingStrategy("id", new SingleKeyTableShardingAlgorithm<Comparable<Integer>>() {

					@Override
					public String doEqualSharding(Collection<String> tableNames, ShardingValue<Comparable<Integer>> shardingValue) {
						for (String each : tableNames) {
				            if (each.endsWith((int)shardingValue.getValue() % 3 + "")) {
				                return each;
				            }
				        }
				        throw new IllegalArgumentException();
					}

					@Override
					public Collection<String> doInSharding(Collection<String> tableNames, ShardingValue<Comparable<Integer>> shardingValue) {
						Collection<String> result = new LinkedHashSet<>(tableNames.size());
				        for (Integer value : (Integer[])shardingValue.getValues().toArray()) {
				            for (String tableName : tableNames) {
				                if (tableName.endsWith(value % 3 + "")) {
				                    result.add(tableName);
				                }
				            }
				        }
				        return result;
					}

					@Override
					public Collection<String> doBetweenSharding(Collection<String> tableNames, ShardingValue<Comparable<Integer>> shardingValue) {
						Collection<String> result = new LinkedHashSet<>(tableNames.size());
				        Range<Comparable<Integer>> range = shardingValue.getValueRange();
				        for (Integer i = (int)range.lowerEndpoint(); i <= (int)range.upperEndpoint(); i++) {
				            for (String each : tableNames) {
				                if (each.endsWith(i % 3 + "")) {
				                    result.add(each);
				                }
				            }
				        }
				        return result;
					}
				}));
		
//		String sql = "select * from t_order where id = ?";
//        try (Connection conn = new ShardingDataSource(shardingRule).getConnection();
//                PreparedStatement pstmt = conn.prepareStatement(sql);
//                ) {
//            pstmt.setInt(1, 2);
//            ResultSet rs = pstmt.executeQuery();
//            while (rs.next()) {
//                System.out.println(rs.getInt(1));
//                System.out.println(rs.getString(2));
//                System.out.println(rs.getInt(3));
//            }
//            rs.close();
//        }
        
		String sql = "insert into t_order (id, name, num) values (?, ?, ?)";
        try (Connection conn = new ShardingDataSource(shardingRule).getConnection();
                PreparedStatement pstmt = conn.prepareStatement(sql);
                ) {
        	pstmt.setInt(1, 8);
        	pstmt.setString(2, "tv");
        	pstmt.setInt(3, 10);
            int result = pstmt.executeUpdate();
            System.out.println("affected rows = " + result);
        }
	}
	
	
	private static DataSource createDataSource(final String dataSourceName) {
	    BasicDataSource result = new BasicDataSource();
	    result.setDriverClassName("net.sf.log4jdbc.DriverSpy");
	    result.setUrl("jdbc:log4jdbc:mysql://localhost:3306/" + dataSourceName);
	    result.setUsername("root");
	    result.setPassword("");
	    return result;
	}

}
